/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * MainForm.java
 *
 * Created on 1-mar-2010, 17.33.09
 */
package lolbatfsm.implementation.gui;

import lolbatfsm.io.FSMStore;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.Box;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import lolbatfsm.implementation.io.FSMFileStore;
import lolbatfsm.io.SimulationController;
import lolbatfsm.io.SimulationListener;
import lolbatfsm.system.AsynchronousTransition;
import lolbatfsm.system.EquivalenceClass;
import lolbatfsm.system.FSM;
import lolbatfsm.system.State;
import lolbatfsm.system.Simulator;
import lolbatfsm.system.SynchronousTransition;
import lolbatfsm.system.Transition;

/**
 * This is the main program's window, which contains the FSM list, the FSM's
 * transitions and all the command buttons.
 * This class implements both the <code>SimulationController</code> interface and the
 * <code>SimulationListener</code> interface.
 * @author Fabio Lola <fadan87@gmail.com>
 */

public class MainForm extends javax.swing.JFrame implements SimulationController, SimulationListener, ActionListener {

    private final Simulator simulator = Simulator.getInstance();
    private Integer nroFSM = 1;
    private FSMStore fsmStore;
    private final HashSet<FSM> fsmSet = new HashSet<FSM>();
    private final Set<EquivalenceClass> equivalenceClassSet =
            new TreeSet<EquivalenceClass>();
    private final HashSet<State> states = new HashSet<State>();
    private String[] statesString;
    boolean ended = false;
    private int totalDuration = 0;

    /** Creates new form MainForm
     *
     *  @param title MainForm's title
     */
    public MainForm(String title) {
        super(title);
        initComponents();
        initialStateCombo.addActionListener(this);
        initialStateCombo.setEditable(false);
        simulator.setSimulationController(this);
        simulator.addSimulationListener(this);
        fsmStore = new FSMFileStore();
        fsmSet.addAll(fsmStore.loadFSMs());
        for (FSM fsm : fsmSet) {
            ((DefaultListModel) fsmListSwing.getModel()).addElement(fsm.getName());
            for (Transition transition : fsm.getTransitions()) {
                if (transition instanceof SynchronousTransition) {
                    if (!equivalenceClassSet.contains(((SynchronousTransition) transition).getEquivalenceClass())) {
                        equivalenceClassSet.add(((SynchronousTransition) transition).getEquivalenceClass());
                    }
                }
            }
        }
        fsmListSwing.validate();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        toolBar = new javax.swing.JToolBar();
        jSeparator5 = new javax.swing.JToolBar.Separator();
        addFSMButton = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JToolBar.Separator();
        renameFSMButton = new javax.swing.JButton();
        jSeparator2 = new javax.swing.JToolBar.Separator();
        removeFSMButton = new javax.swing.JButton();
        jSeparator3 = new javax.swing.JToolBar.Separator();
        editEqClassButton = new javax.swing.JButton();
        jSeparator4 = new javax.swing.JToolBar.Separator();
        startSimulation = new javax.swing.JButton();
        jSeparator6 = new javax.swing.JToolBar.Separator();
        saveButton = new javax.swing.JButton();
        jSeparator7 = new javax.swing.JToolBar.Separator();
        jSplitPane1 = new javax.swing.JSplitPane();
        leftPanel = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        fsmListSwing = new javax.swing.JList();
        rightPanel = new javax.swing.JPanel();
        applyButton = new javax.swing.JButton();
        sourceLabel = new javax.swing.JLabel();
        destinationLabel = new javax.swing.JLabel();
        durationLabel = new javax.swing.JLabel();
        eqClassLabel = new javax.swing.JLabel();
        synchLabel = new javax.swing.JLabel();
        addTransitionButton = new javax.swing.JButton();
        itemScrollPane = new javax.swing.JScrollPane();
        itemsPanel = new javax.swing.JPanel();
        initialStateCombo = new javax.swing.JComboBox();
        initialStateLabel = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                mainFormClosing(evt);
            }
        });

        toolBar.setFloatable(false);
        toolBar.setRollover(true);
        toolBar.setPreferredSize(new java.awt.Dimension(100, 32));

        jSeparator5.setSeparatorSize(new java.awt.Dimension(5, 0));
        toolBar.add(jSeparator5);

        addFSMButton.setText("Add FSM");
        addFSMButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        addFSMButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                addFSMButtonClicked(evt);
            }
        });
        toolBar.add(addFSMButton);

        jSeparator1.setSeparatorSize(new java.awt.Dimension(5, 0));
        toolBar.add(jSeparator1);

        renameFSMButton.setText("Rename FSM");
        renameFSMButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        renameFSMButton.setEnabled(false);
        renameFSMButton.setFocusable(false);
        renameFSMButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        renameFSMButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        renameFSMButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                renameFSMButtonMouseClicked(evt);
            }
        });
        toolBar.add(renameFSMButton);

        jSeparator2.setSeparatorSize(new java.awt.Dimension(5, 0));
        toolBar.add(jSeparator2);

        removeFSMButton.setText("Remove FSM");
        removeFSMButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        removeFSMButton.setEnabled(false);
        removeFSMButton.setFocusable(false);
        removeFSMButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        removeFSMButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        removeFSMButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                removeFSMMouseClicked(evt);
            }
        });
        toolBar.add(removeFSMButton);

        jSeparator3.setSeparatorSize(new java.awt.Dimension(5, 0));
        toolBar.add(jSeparator3);

        editEqClassButton.setText("Edit Equivalence Classes");
        editEqClassButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        editEqClassButton.setFocusable(false);
        editEqClassButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        editEqClassButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        editEqClassButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                editEqClassButtonMouseClicked(evt);
            }
        });
        toolBar.add(editEqClassButton);

        jSeparator4.setSeparatorSize(new java.awt.Dimension(5, 0));
        toolBar.add(jSeparator4);

        startSimulation.setText("Start Simulation");
        startSimulation.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        startSimulation.setFocusable(false);
        startSimulation.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        startSimulation.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        startSimulation.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                startSimulationClicked(evt);
            }
        });
        toolBar.add(startSimulation);

        jSeparator6.setSeparatorSize(new java.awt.Dimension(5, 0));
        toolBar.add(jSeparator6);

        saveButton.setText("Save");
        saveButton.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        saveButton.setFocusable(false);
        saveButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        saveButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        saveButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                saveButtonClicked(evt);
            }
        });
        toolBar.add(saveButton);

        jSeparator7.setSeparatorSize(new java.awt.Dimension(5, 0));
        toolBar.add(jSeparator7);

        jSplitPane1.setDividerLocation(200);
        jSplitPane1.setMinimumSize(new java.awt.Dimension(0, 0));

        fsmListSwing.setModel(new DefaultListModel());
        fsmListSwing.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        fsmListSwing.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                fsmListSwingValueChanged(evt);
            }
        });
        jScrollPane1.setViewportView(fsmListSwing);

        org.jdesktop.layout.GroupLayout leftPanelLayout = new org.jdesktop.layout.GroupLayout(leftPanel);
        leftPanel.setLayout(leftPanelLayout);
        leftPanelLayout.setHorizontalGroup(
            leftPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE)
        );
        leftPanelLayout.setVerticalGroup(
            leftPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 566, Short.MAX_VALUE)
        );

        jSplitPane1.setLeftComponent(leftPanel);

        rightPanel.setAutoscrolls(true);

        applyButton.setText("Apply Changes");
        applyButton.setVisible(false);
        applyButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                applyButtonMouseClicked(evt);
            }
        });

        sourceLabel.setText("Source state");
        sourceLabel.setVisible(false);

        destinationLabel.setText("Destination state");
        destinationLabel.setVisible(false);

        durationLabel.setText("Duration");
        durationLabel.setVisible(false);

        eqClassLabel.setText("Equivalence class");
        eqClassLabel.setVisible(false);

        synchLabel.setText("Synchronous");
        synchLabel.setVisible(false);

        addTransitionButton.setText("Add transition");
        addTransitionButton.setVisible(false);
        addTransitionButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                addTransitionMouseClicked(evt);
            }
        });

        itemScrollPane.setBorder(null);

        itemsPanel.setLayout(new java.awt.GridBagLayout());
        itemScrollPane.setViewportView(itemsPanel);

        initialStateCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        initialStateCombo.setVisible(false);

        initialStateLabel.setText("Initial State");
        initialStateLabel.setVisible(false);

        org.jdesktop.layout.GroupLayout rightPanelLayout = new org.jdesktop.layout.GroupLayout(rightPanel);
        rightPanel.setLayout(rightPanelLayout);
        rightPanelLayout.setHorizontalGroup(
            rightPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(rightPanelLayout.createSequentialGroup()
                .add(rightPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, rightPanelLayout.createSequentialGroup()
                        .add(46, 46, 46)
                        .add(sourceLabel)
                        .add(92, 92, 92)
                        .add(destinationLabel)
                        .add(53, 53, 53)
                        .add(synchLabel)
                        .add(18, 18, 18)
                        .add(durationLabel)
                        .add(39, 39, 39)
                        .add(eqClassLabel)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 28, Short.MAX_VALUE)
                        .add(addTransitionButton))
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, rightPanelLayout.createSequentialGroup()
                        .addContainerGap(394, Short.MAX_VALUE)
                        .add(initialStateLabel)
                        .add(18, 18, 18)
                        .add(initialStateCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 122, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                        .add(applyButton)))
                .addContainerGap())
            .add(itemScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 714, Short.MAX_VALUE)
        );
        rightPanelLayout.setVerticalGroup(
            rightPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(rightPanelLayout.createSequentialGroup()
                .add(11, 11, 11)
                .add(rightPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(addTransitionButton)
                    .add(sourceLabel)
                    .add(eqClassLabel)
                    .add(destinationLabel)
                    .add(durationLabel)
                    .add(synchLabel))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(itemScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 486, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(rightPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(applyButton)
                    .add(initialStateCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(initialStateLabel))
                .addContainerGap())
        );

        jSplitPane1.setRightComponent(rightPanel);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jSplitPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 920, Short.MAX_VALUE)
            .add(toolBar, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 920, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(toolBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jSplitPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 568, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    /**
     * This method ask user to input FSM's name and add the FSM in the FSMs list
     */
    private void addFSMButtonClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_addFSMButtonClicked
        String fsmName = null;
        Boolean exist = false;
        Boolean nroExist = false;
        do {
            nroExist = false;
            for (int i = 0; i < fsmListSwing.getModel().getSize(); i++) {
                if (((String) fsmListSwing.getModel().getElementAt(i)).equals("FSM" + Integer.toString(nroFSM))) {
                    nroExist = true;
                }
            }
            if (nroExist) {
                nroFSM++;
            }
        } while (nroExist);
        do {
            exist = false;
            fsmName = JOptionPane.showInputDialog("FSM Name", "FSM" + Integer.toString(nroFSM));
            for (int i = 0; i < fsmListSwing.getModel().getSize(); i++) {
                if (((String) fsmListSwing.getModel().getElementAt(i)).equals(fsmName)) {
                    exist = true;
                }
            }
            if (exist) {
                JOptionPane.showMessageDialog(null, fsmName + " already exists, choose another name", "ERROR", JOptionPane.ERROR_MESSAGE);
            } else if (fsmName != null && (fsmName.equals("") || fsmName.matches(" *"))) {
                JOptionPane.showMessageDialog(null, "Void String, please re-type FSM's name", "ERROR", JOptionPane.ERROR_MESSAGE);
                exist = true;
            }
        } while (exist);
        if (fsmName != null) {
            ((DefaultListModel) fsmListSwing.getModel()).addElement(fsmName);
            fsmListSwing.setSelectedValue(fsmName, false);
            fsmListSwing.validate();
            State sourceState = new State("Initial");
            Transition transition = new AsynchronousTransition(sourceState, new State("Second"), 1);
            Transition[] transitions = new Transition[1];
            transitions[0] = transition;
            FSM fsm = new FSM(fsmName, sourceState, transitions);
            fsmSet.add(fsm);
            itemsPanel.removeAll();
            createFSMPanel(fsmName);
        }
    }//GEN-LAST:event_addFSMButtonClicked

    /**
     * This method apply all changes to the selected FSM, receiving data
     * from the FSM's ItemPanel.
     * It also update all older comboboxes with new states from new transitions.
     *
     * @param fsmName FSM name
     */
    private void applyChanges(String fsmName) {
        Transition[] transitions;
        Collection<Transition> transitionList = new TreeSet<Transition>();
        FSM oldFSM = null;
        FSM newFSM = null;
        states.clear();
        for (FSM fsm : fsmSet) {
            if (fsm.getName().equals(fsmName)) {
                for (int i = 0; i < itemsPanel.getComponents().length; i++) {
                    if (itemsPanel.getComponent(i) instanceof ItemPanel) {
                        if (((ItemPanel) itemsPanel.getComponent(i)).getStates() == null) {
                            JOptionPane.showMessageDialog(null, "Void State, please re-type state", "ERROR", JOptionPane.ERROR_MESSAGE);
                            return;
                        } else {
                            states.addAll(((ItemPanel) itemsPanel.getComponent(i)).getStates());
                            Transition transition = ((ItemPanel) itemsPanel.getComponent(i)).getTransition();
                            if (transition == null) {
                                JOptionPane.showMessageDialog(null, "Invalid duration (0 or null), please re-type duration", "ERROR", JOptionPane.ERROR_MESSAGE);
                                return;
                            } else {
                                transitionList.add(transition);
                                if (transition instanceof SynchronousTransition) {
                                    equivalenceClassSet.addAll(((ItemPanel) itemsPanel.getComponent(i)).getEquivalenceClasses());
                                }
                            }
                        }
                    }
                }
                for (int i = 0; i < itemsPanel.getComponents().length; i++) {
                    if (itemsPanel.getComponent(i) instanceof ItemPanel) {
                        ((ItemPanel) itemsPanel.getComponent(i)).setComboBoxes(states, equivalenceClassSet);
                        ((ItemPanel) itemsPanel.getComponent(i)).validate();
                    }
                }
                transitions = new Transition[transitionList.size()];
                transitionList.toArray(transitions);
                String initialStateString = (String) initialStateCombo.getSelectedItem();
                State initialState = null;
                statesString = new String[states.size()];
                int i = 0;
                for (State state : states) {
                    statesString[i] = state.getName();
                    if (state.getName().equals(initialStateString)) {
                        initialState = state;
                    }
                    i++;
                }
                if (initialState == null) {
                    for (State state : states) {
                        if (initialState == null) {
                            initialState = state;
                        }
                    }
                }
                initialStateCombo.setModel(new javax.swing.DefaultComboBoxModel(statesString));
                initialStateCombo.setSelectedItem(initialState.toString());
                newFSM = new FSM(fsm.getName(), initialState, transitions);
                oldFSM = fsm;
                fsmListSwing.setSelectedValue(newFSM.getName(), false);
            }
        }
        fsmSet.remove(oldFSM);
        fsmSet.add(newFSM);
        applyButton.setEnabled(false);
    }

    /**
     * Launch applyChanges when the button is clicked
     */
    private void applyButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_applyButtonMouseClicked
        if(applyButton.isEnabled()){
            applyChanges((String) fsmListSwing.getSelectedValue());
            applyButton.setEnabled(false);
        }
    }//GEN-LAST:event_applyButtonMouseClicked

    /**
     * Catch the selected FSM and shows its Itempanels
     */
    private void fsmListSwingValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_fsmListSwingValueChanged
        if (fsmListSwing.getSelectedValue() != null && !evt.getValueIsAdjusting()) {
            itemsPanel.removeAll();
            createFSMPanel((String) fsmListSwing.getSelectedValue());
            addTransitionButton.setEnabled(true);
            renameFSMButton.setEnabled(true);
            removeFSMButton.setEnabled(true);
            initialStateCombo.setEnabled(true);
        }
        else{
            renameFSMButton.setEnabled(false);
            removeFSMButton.setEnabled(false);
            applyButton.setEnabled(false);
            initialStateCombo.setEnabled(false);
        }
    }//GEN-LAST:event_fsmListSwingValueChanged

    /**
     * Add new transition to the selected FSM
     */
    private void addTransitionMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_addTransitionMouseClicked
        if (addTransitionButton.isEnabled()) {
            FSM oldFSM = null;
            FSM newFSM = null;
            applyChanges((String) fsmListSwing.getSelectedValue());
            for (FSM fsm : fsmSet) {
                if (fsm.getName().equals(fsmListSwing.getSelectedValue())) {
                    oldFSM = fsm;
                    Transition[] transitions;
                    State sourceState = new State("source state");
                    State destinationState = new State("destination state");
                    transitions = new Transition[oldFSM.getTransitions().size() + 1];
                    oldFSM.getTransitions().toArray(transitions);
                    boolean found = false;
                    for (int i = itemsPanel.getComponentCount() - 1; i >= 0; i--) {
                        if (itemsPanel.getComponent(i) instanceof ItemPanel && !found) {
                            found = true;
                            for (State state : states) {
                                if (state.getName().equals(((ItemPanel) itemsPanel.getComponent(i)).getDestinationStateString())) {
                                    sourceState = state;
                                }
                            }
                        }
                    }
                    Transition transition = new AsynchronousTransition(sourceState, destinationState, 1);
                    transitions[oldFSM.getTransitions().size()] = transition;
                    newFSM = new FSM(oldFSM.getName(), oldFSM.getCurrentState(), transitions);
                }
            }
            fsmSet.remove(oldFSM);
            fsmSet.add(newFSM);
            ((DefaultListModel) fsmListSwing.getModel()).removeElement(oldFSM.getName());
            ((DefaultListModel) fsmListSwing.getModel()).addElement(newFSM.getName());
            fsmListSwing.setSelectedValue(newFSM.getName(), false);
            itemsPanel.removeAll();
            applyButton.setEnabled(true);
            createFSMPanel((String) fsmListSwing.getSelectedValue());
        }
    }//GEN-LAST:event_addTransitionMouseClicked

    /**
     * Remove the selected FSM
     */
    private void removeFSMMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_removeFSMMouseClicked
        if (removeFSMButton.isEnabled()) {
            int choose = JOptionPane.showConfirmDialog(null, "Remove FSM?");
            if (choose == JOptionPane.YES_OPTION) {
                FSM oldFSM = null;
                for (FSM fsm : fsmSet) {
                    if (fsm.getName().equals(fsmListSwing.getSelectedValue())) {
                        oldFSM = fsm;
                        ((DefaultListModel) fsmListSwing.getModel()).removeElement(fsm.getName());
                        fsmListSwing.validate();
                    }
                }
                itemsPanel.removeAll();
                itemsPanel.repaint();
                itemsPanel.validate();
                applyButton.setEnabled(false);
                addTransitionButton.setEnabled(false);
                initialStateCombo.setEnabled(false);
                fsmSet.remove(oldFSM);
            }
        }
    }//GEN-LAST:event_removeFSMMouseClicked

    
    private void mainFormClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_mainFormClosing
    }//GEN-LAST:event_mainFormClosing

    /**
     * Start simulation
     */
    private void startSimulationClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_startSimulationClicked
        if (fsmSet.size() > 0) {
            for (FSM fsm : fsmSet) {
                fsm.init();
            }
            simulator.startSimulation(fsmSet, equivalenceClassSet);
        }
    }//GEN-LAST:event_startSimulationClicked
    /**
     * This method create a form where user can modify one of the equivaelnce
     * classes
     */
    private void editEqClassButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_editEqClassButtonMouseClicked
        if (equivalenceClassSet.size() > 0) {
            EqClassGUI eqClassGUI = EqClassGUI.createAndShow(equivalenceClassSet, fsmSet);
            if (fsmListSwing.getSelectedValue() != null) {
                itemsPanel.removeAll();
                createFSMPanel((String) fsmListSwing.getSelectedValue());
            }
        }
    }//GEN-LAST:event_editEqClassButtonMouseClicked

    /**
     * This method ask user to input new name for the selected FSM
     */
    private void renameFSMButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_renameFSMButtonMouseClicked
        if (renameFSMButton.isEnabled()) {
            Boolean exist = false;
            String fsmName = null;
            String fsmNameOld = (String) fsmListSwing.getSelectedValue();
            if (fsmNameOld != null) {
                do {
                    exist = false;
                    fsmName = JOptionPane.showInputDialog("FSM Name", fsmNameOld);
                    for (int i = 0; i < fsmListSwing.getModel().getSize(); i++) {
                        if (((String) fsmListSwing.getModel().getElementAt(i)).equals(fsmName) && !fsmName.equals(fsmNameOld)) {
                            exist = true;
                        }
                    }
                    if (exist) {
                        JOptionPane.showMessageDialog(null, fsmName + " already exists, choose another name", "ERROR", JOptionPane.ERROR_MESSAGE);
                    } else if (fsmName != null && (fsmName.equals("") || fsmName.matches(" *"))) {
                        JOptionPane.showMessageDialog(null, "Void String, please re-type FSM's name", "ERROR", JOptionPane.ERROR_MESSAGE);
                        exist = true;
                    }
                } while (exist);
            }
            if (fsmName != null) {
                FSM oldFSM = null;
                FSM newFSM = null;
                boolean found = false;
                applyChanges(fsmNameOld);
                if (fsmName != null) {
                    ((DefaultListModel) fsmListSwing.getModel()).removeElement(fsmNameOld);
                    ((DefaultListModel) fsmListSwing.getModel()).addElement(fsmName);
                    fsmListSwing.validate();
                    renameFSMButton.setEnabled(false);
                    Transition[] transitions;
                    Collection<Transition> transitionList = new TreeSet<Transition>();
                    for (FSM fsm : fsmSet) {
                        if (fsm.getName().equals(fsmNameOld)) {
                            found = true;
                            oldFSM = fsm;
                            transitionList = fsm.getTransitions();
                            transitions = new Transition[transitionList.size()];
                            transitionList.toArray(transitions);
                            newFSM = new FSM(fsmName, fsm.getCurrentState(), transitions);
                        }
                    }
                    if (found) {
                        fsmSet.remove(oldFSM);
                        fsmSet.add(newFSM);
                    }
                }
            }
        }
}//GEN-LAST:event_renameFSMButtonMouseClicked
    /**
     * Save all FSMs in a file
     */
    private void saveButtonClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_saveButtonClicked
        fsmStore.storeFSMs(fsmSet);
    }//GEN-LAST:event_saveButtonClicked
    // Variables declaration - do not modify//GEN-BEGIN:variables
    public javax.swing.JButton addFSMButton;
    private javax.swing.JButton addTransitionButton;
    public javax.swing.JButton applyButton;
    private javax.swing.JLabel destinationLabel;
    private javax.swing.JLabel durationLabel;
    private javax.swing.JButton editEqClassButton;
    private javax.swing.JLabel eqClassLabel;
    private javax.swing.JList fsmListSwing;
    private javax.swing.JComboBox initialStateCombo;
    private javax.swing.JLabel initialStateLabel;
    private javax.swing.JScrollPane itemScrollPane;
    public javax.swing.JPanel itemsPanel;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JToolBar.Separator jSeparator1;
    private javax.swing.JToolBar.Separator jSeparator2;
    private javax.swing.JToolBar.Separator jSeparator3;
    private javax.swing.JToolBar.Separator jSeparator4;
    private javax.swing.JToolBar.Separator jSeparator5;
    private javax.swing.JToolBar.Separator jSeparator6;
    private javax.swing.JToolBar.Separator jSeparator7;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JPanel leftPanel;
    private javax.swing.JButton removeFSMButton;
    private javax.swing.JButton renameFSMButton;
    public javax.swing.JPanel rightPanel;
    private javax.swing.JButton saveButton;
    private javax.swing.JLabel sourceLabel;
    private javax.swing.JButton startSimulation;
    private javax.swing.JLabel synchLabel;
    private javax.swing.JToolBar toolBar;
    // End of variables declaration//GEN-END:variables

    /**
     * Implements method from SimulationController.<br>
     * It shows a Form where the user can select transitions that have to iterate
     */
    public Integer[][] selectTransitions(ArrayList<AsynchronousTransition> selectableAsyncTransitions, ArrayList<? extends Collection<SynchronousTransition>> selectableSyncTransitions, boolean allowNullSelection) {
        SimulatorGUI simulatorGUI = SimulatorGUI.createAndShow(selectableAsyncTransitions, selectableSyncTransitions, allowNullSelection, this);
        return simulatorGUI.getIterationResult();
    }

    /**
     * Implements method from SimulationController.<br>
     * It reports errors
     * @param string
     */
    public void errorOccurred(String string) {
        if (ended) {
            simulator.stopSimulation();
        } else {
            JOptionPane.showMessageDialog(null, string, "ERROR", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Implements method from SimulationListener.<br>
     * It shows the iteration's results
     */
    public void iterationCompleted(int iterationDuration, Collection<FSM> fsms) {
        totalDuration += iterationDuration;
        IterationGUI iterationGUI = IterationGUI.createAndShow(iterationDuration, fsms, totalDuration);
        if (iterationGUI.isSimulationStopped()) {
            simulator.stopSimulation();
        }
    }

    /**
     * Implements method from SimulationListener.<br>
     * It notifies simulation's ending
     */
    public void simulationEnded() {
        JOptionPane.showMessageDialog(null, "Simulation ended.", "End", JOptionPane.INFORMATION_MESSAGE);
        totalDuration = 0;
    }

    /**
     * Create and show the JScrollPanel which contains the ItemPanels associated
     * to the selected FSM.
     *
     * @param fsmName selected FSM's name
     */
    private void createFSMPanel(String fsmName) {
        Collection<Transition> transitions;
        State initialState = null;
        states.clear();
        //Creazione etichette
        GridBagLayout gridBagLayout = new GridBagLayout();
        GridBagConstraints tc = new GridBagConstraints();
        sourceLabel.setPreferredSize(new Dimension(70, 20));
        destinationLabel.setPreferredSize(new Dimension(90, 20));
        synchLabel.setPreferredSize(new Dimension(70, 20));
        durationLabel.setPreferredSize(new Dimension(50, 20));
        eqClassLabel.setPreferredSize(new Dimension(90, 20));
        addTransitionButton.setPreferredSize(new Dimension(100, 20));
        sourceLabel.setVisible(true);
        destinationLabel.setVisible(true);
        durationLabel.setVisible(true);
        synchLabel.setVisible(true);
        eqClassLabel.setVisible(true);
        addTransitionButton.setVisible(true);
        initialStateCombo.setVisible(true);
        initialStateLabel.setVisible(true);
        for (FSM fsm : fsmSet) {
            if (fsm.getName().equals(fsmName)) {
                transitions = fsm.getTransitions();
                initialState = fsm.getCurrentState();
                for (Transition transition : transitions) {
                    if (!states.contains(transition.getSourceState())) {
                        states.add(transition.getSourceState());
                    }
                    if (!states.contains(transition.getDestinationState())) {
                        states.add(transition.getDestinationState());
                    }
                }
                statesString = new String[states.size()];
                int i = 0;
                for (State state : states) {
                    statesString[i] = state.getName();
                    i++;
                }
                initialStateCombo.setModel(new javax.swing.DefaultComboBoxModel(statesString));
                initialStateCombo.setSelectedItem(initialState.toString());
                tc.anchor = GridBagConstraints.NORTHWEST;
                tc.weightx = 0.5;
                tc.weighty = 0.0;
                tc.gridx = 0;
                tc.gridy = 0;
                tc.insets = new Insets(10, 30, 10, 0);
                boolean first = true;
                for (Transition transition : transitions) {
                    ItemPanel itemPanel = new ItemPanel(transition, states, equivalenceClassSet, this, first);
                    itemsPanel.add(itemPanel);
                    gridBagLayout.setConstraints(itemPanel, tc);
                    ++tc.gridy;
                    first = false;
                }
            }
        }
        tc.weighty = 1.0;
        tc.gridheight = GridBagConstraints.REMAINDER;
        itemsPanel.setLayout(gridBagLayout);
        itemsPanel.add(Box.createVerticalGlue(), tc);
        applyButton.setVisible(true);
        itemsPanel.repaint();
        itemsPanel.validate();
        rightPanel.repaint();
        rightPanel.validate();
    }

    /**
     * Implements method from java.awt.event.ActionListener
     * @param e
     */
    public void actionPerformed(ActionEvent e) {
        applyButton.setEnabled(true);
    }
}
